#!/bin/ksh
#
###########################################################################
# The parsing of the versionlog is a difficult matter ...
# (mbligh, apw)
###########################################################################
#
# $Copyright: $
# Copyright (c) 1984-1998
# Sequent Computer Systems, Inc.   All rights reserved.
#  
# This software is furnished under a license and may be used
# only in accordance with the terms of that license and with the
# inclusion of the above copyright notice.   This software may not
# be provided or otherwise made available to, or used by, any
# other person.  No title to or ownership of the software is
# hereby transferred.
# 
# ident  "$Id: getv,v 1.2 02/03/11 20:40:12 wwtsfp Exp $"
#
###########################################################################

versionlog="/etc/versionlog"
debug=0
quiet=0
test=0
printfp=0             # aka Pflg

if [ `/bin/basename $0` = "vlext" ]; then
	# behave as vlext
	USAGE="Usage: vlext [-d] [-p product] [-P] [versionlog]"
	appzero=0

	while getopts dp:qPT c
	do
		case $c in
			d)          debug=1;;
			p)          product=$OPTARG;;
			q)          quiet=1;;
			P)          printfp=1;;
			T)          test=1;;
			\?)         echo $USAGE 1>&2; exit 2;;
		esac
	done
	shift `expr $OPTIND - 1`
	if [ $# -eq 0 ]; then
		versionlog="/etc/versionlog"
	elif [ $# -eq 1 ]; then
		versionlog="$1"
	else
		echo $USAGE 1>&2
		exit 1
	fi
else
	USAGE="Usage: vcheck [-d] [-v versionlog] product"
	appzero=1

	while getopts dv: c
	do
		case $c in
			d)          debug=1;;
			v)			versionlog=$OPTARG;;
			\?)         echo $USAGE 1>&2; exit 2;;
		esac
	done
	shift `expr $OPTIND - 1`
	if [ $# -ne 1 ]; then
		echo $USAGE 1>&2
		exit 1
	fi
	vcheck="$1"
fi

#
# Check for the VLOG not being readable.
#
if [ ! -r "$versionlog" ]; then
    echo "$versionlog: versionlog not accessible." 1>&2
    exit 1
fi

/usr/bin/nawk '
BEGIN {
	FS = "[ \t]+"

# Do NOT put more than 99 elements in an assoc array - nawk is broken.

	nickname["C++ translator"] = "C++"
	nickname["Backup Toolkit"] = "bktk"
	nickname["C compiler and Language Tools"] = "ctools"
	nickname["CSM SW"] = "csm"
	nickname["DYNIX/ptx SLS(TM) Base"] = "sls"
	nickname["DYNIX/ptx(R) Base"] = "ptx"
	nickname["DYNIX/ptx(R) Base Update"] = "ptx"
	nickname["DYNIX/ptx(R) Encryption"] = "encryption"
	nickname["DYNIX/ptx(R) Encryption Software"] = "encryption"
	nickname["DYNIX/ptx(R) Public Software"] = "public"
	nickname["FCBRIDGE SW"] = "fcbr"
	nickname["FCSWITCH SW"] = "fcsw"
	nickname["FORTRAN compiler"] = "fortran"
	nickname["NETWARE for Sequent Information Servers"] = "netware"
	nickname["Netware for Sequent IS"] = "netware"
	nickname["Netware for Sequent Information Servers"] = "netware"
	nickname["Online Diagnostic Software"] = "online-diags-symmetry"
	nickname["Online Diags"] = "online-diags-symmetry"
	nickname["Pascal compiler"] = "pascal"
	nickname["ProScan"] = "proscan"
	nickname["QCIC FW"] = "qcic"
	nickname["QCIC SW"] = "qcic"
	nickname["QCIC_SW"] = "qcic"
	nickname["SSM SW"] = "ssm"
	nickname["SequentLINK"] = "sqntlink"
	nickname["TRUSTED/ptx(TM) Base"] = "trusted"
	nickname["TRUSTED/ptx(TM) Base Update"] = "trusted"
	nickname["ptx/AGENT Subagent Development Kit"] = "agent-sdk"
	nickname["ptx/AGENT SDK"] = "agent-sdk"
	nickname["ptx/AGENT"] = "agent"
	nickname["ptx/ANSI-C product"] = "ansic"
	nickname["ptx/ARGUS"] = "argus"
	nickname["ptx/ATM"] = "atm"
	nickname["ptx/BaseComms"] = "basecomms"
	nickname["ptx/BACKUP"] = "backup"
	nickname["ptx/BACKUP/server"] = "backup"
	nickname["ptx/C++"] = "C++"
	nickname["ptx/CDFS"] = "cdfs"
	nickname["ptx/CFS"] = "cfs"
	nickname["ptx/CLUSTERS"] = "clusters"
	nickname["ptx/COBOL"] = "cobol"
	nickname["ptx/CTC"] = "ctc"
	nickname["ptx/DLT"] = "dlt"
	nickname["ptx/DNA"] = "dna"
	nickname["ptx/DTI"] = "dti"
	nickname["ptx/EES"] = "ees"
	nickname["ptx/EFS"] = "efs"
	nickname["ptx/ESBM"] = "esbm"
	nickname["ptx/ETP"] = "etp"
	nickname["ptx/FRAMEMAKER"] = "framemaker"
	nickname["ptx/FTAM File Services"] = "ftam"
	nickname["ptx/FTAM File Services"] = "ftam"
	nickname["ptx/INSTALL"] = "install"
	nickname["ptx/ITX"] = "itx"
	nickname["ptx/JSE"] = "jse"
	nickname["ptx/JUKEBOX"] = "jb"
	nickname["ptx/LAN"] = "lan"
	nickname["ptx/LAT"] = "lat"
	nickname["ptx/LICENSE"] = "license"
	nickname["ptx/NFS"] = "nfs"
	nickname["ptx/NQS"] = "nqs"
	nickname["ptx/ORACLEASM"] = "oracleasm"
	nickname["ptx/OSBM"] = "osbm"
	nickname["ptx/OSI Transport Services"] = "osi"
	nickname["ptx/PDC"] = "pdc"
	nickname["ptx/PEP"] = "pep"
	nickname["ptx/RAID"] = "raid"
	nickname["ptx/RPC"] = "rpc"
	nickname["ptx/SILO"] = "silo"
	nickname["ptx/SLPT"] = "slpt"
	nickname["ptx/SNA 3270"] = "sna3270"
	nickname["ptx/SNA TN3270"] = "snaTN3270"
	nickname["ptx/SNA TN3270 Server"] = "snaTN3270server"
	nickname["ptx/SNA 3770"] = "sna3770"
	nickname["ptx/SNA APPC"] = "snaappc"
	nickname["ptx/SNA LU0 API"] = "snaLU0API"
	nickname["ptx/SNA LU62 Server"] = "snaLU62"
	nickname["ptx/SNA PU21 Server"] = "snaPU21"
	nickname["ptx/SNA RJE"] = "snarje"
	nickname["ptx/SNA SDLC & LLCI"] = "snakernel"
	nickname["ptx/SNA Base Services"] = "snabase"
	nickname["ptx/SNA Base"] = "snabase"
	nickname["ptx/SPDRIVERS"] = "spd"
	nickname["ptx/SVM"] = "svm"
	nickname["ptx/SYNC"] = "sync"
	nickname["ptx/TCP"] = "tcp"
	nickname["ptx/TCP/IP"] = "tcp"
	nickname["ptx/VJ"] = "vj"
	nickname["ptx/WINDOWS"] = "windows"
	nickname["ptx/WINDOWS Contributed"] = "windows-contrib"
	nickname["ptx/WINDOWS - Contributed"] = "windows-contrib"
	nickname["ptx/X.25"] = "x25"
	nickname["ptx/transACTION"] = "transaction"
	nickname["ptx/x400 Base Services"] = "x400"
	nickname["ptx/x400 Base Services"] = "x400b"
	nickname["ptx/x400 Sendmail Gateway"] = "x400s"

# Do NOT put more than 99 elements in an assoc array - nawk is broken.

	nickname2["Alexandria"] = "alexandria"
	nickname2["ptx/4.5GB_DISK"] = "4_5gb"
	nickname2["ptx/9GB_DISK"] = "9gb"
	nickname2["ptx/18GB_DISK"] = "18gb"
	nickname2["ptx/HITACHI-RAIDMP"] = "raidmp"
	nickname2["ptx/XWM"] = "xwm"
	nickname2["ptx/XWM Contributed"] = "xwm-contrib"
	nickname2["Netscape FastTrack Server"] = "nfts"
	nickname2["ptx/NWS"] = "nws"
# FHCA versions in the versionlog are random misinformation. Look at showcfg.
#	nickname2["Fibre Channel Host Adapter FW"] = "fcha"
#	nickname2["Fibre Channel Host Adapter SW"] = "fcha"
	nickname2["Fibre Channel Switch FW"] = "fcsw"
	nickname2["Fibre Channel Switch SW"] = "fcsw"
	nickname2["ptx/ORIENTEER"] = "orienteer"
	nickname2["ptx/ORIENTEER(TM) Document Viewer"] = "orienteer"
	nickname2["ptx/CKM"] = "ckm"
	nickname2["ptx/C++ Runtime"] = "C++R"
	nickname2["CommandPoint Base"] = "cp-base"
	nickname2["CommandPoint Admin"] = "cp-admin"
	nickname2["CommandPoint SVM"] = "cp-svm"
	nickname2["CommandPoint Clusters"] = "cp-clusters"
	nickname2["Seagate Disk FW"] = "seagate-fw"
	nickname2["ptx/edb"] = "edb"
	nickname2["ptx/NIHONGO"] = "nihongo"
	nickname2["MQSeries for DYNIX/ptx"] = "mqseries"
	nickname2["CFWDL FW Bundle"] = "fw_bundle"
	nickname2["IBM Fibre Channel 36GB Disk FW"] = "ibmdisk_36"

	patchname["ALEXANDRIA"] = "alexandria"        
	patchname["AGENT"] = "agent";        patchname["agent"] = "agent"
	patchname["ATM"] = "atm";            patchname["atm"] = "atm"
	patchname["Base"] = "ptx";           patchname["base"] = "ptx"
	patchname["CFS"] = "cfs";            patchname["cfs"] = "cfs"
	patchname["CLUSTERS"] = "clusters";  patchname["clusters"] = "clusters"  
	patchname["CTC"] = "ctc";            patchname["ctc"] = "ctc"
	patchname["EFS"] = "efs";            patchname["efs"] = "efs"
	patchname["fcbr"] = "fcbr"
	patchname["fcswitch"] = "fcsw"
	patchname["install"] = "install"
	patchname["LAN"] = "lan";
	patchname["NFS"] = "nfs";            patchname["nfs"] = "nfs"
	patchname["PDC"] = "pdc";            patchname["pdc"] = "pdc"
	patchname["RAID"] = "raid";          patchname["raid"] = "raid"
	patchname["SPDRIVERS"] = "spd";      patchname["spdrivers"] = "spd"
	patchname["SVM"] = "svm";            patchname["svm"] = "svm"
	patchname["TCP"] = "tcp";            patchname["tcp"] = "tcp"
#	patchname["FCHA"] = "fcha";

	fptoeng["FP#239782"] = "Patch#SVM_V2.0.2.3";
	fptoeng["FP#229584"] = "Patch#TCP_V4.2.2.1";
	fptoeng["FP#244477"] = "Patch#ALEXANDRIA_V4.00.97";
	fptoeng["FP#244778"] = "Patch#ALEXANDRIA_V4.00.97";
	fptoeng["FP#247041"] = "Patch#ALEXANDRIA_V4.50.51";

	engtoeng["Patch#1003-75871-01"] = "Patch#FCHA_V2.12";
	engtoeng["Patch#1003-74429-00"] = "Patch#Base_V4.4.2.1";
	engtoeng["Patch#237245"] = "Patch#SVM_V2.0.2.1";
	engtoeng["Patch#1003-74430-00:v2.0.0:spdrivers"] = "Patch#SPDRIVERS_V2.0.0.A";
}

function prdebug(STRING) {
	if (debug == 1) { print STRING, origline | "cat 1>&2" }
}

{
	# dispose of date - new style. Intended to be robust against date formats

	rawline = $0
	while ($0 !~ "^([^ \t]+:| *-)[ \t]") {     # not done yet ...
		oldline = $0
		sub ("^[^ \t]+[ \t]+", "")
		if (oldline == $0) {       
			# we are not getting anywhere - danger of infinite loop
			origline = "{" rawline "}"
			prdebug("u - - -") 
			next
		}
	}
	sub ("^([^ \t]+:| *-)[ \t]+", "")
	origline = "{" $0 "}"
}

/^FP#/ {                                 # BR comments
	next 
}  

/^Fastpatch FP#[0-9]+\.[0-9]+ / {                          # service fastpatch
	if ($4 == "complete") {
		method = $3
		sub ("^Fastpatch *FP#", "FP#")
		sub ("\\..*", "")
		if (method == "install") {
			prdebug("f i - " $1)
			fpinst[$1] = 1
			line[$1] = NR
		}
		if (method == "deinstall") {
			prdebug("f d - " $1)
			delete fpinst[$1]
			delete line[$1]
		}
	}
	if ($1 in fptoeng) { $0 = fptoeng[$1] " - " method }
	else { next }
}
	
/^Patch#/ {                              # engineering patch
	if ($1 ~ "^Patch#1003-73386-0") {
		split($1, fields, ":") 
		if (fields[1] ~ "0$") { patchrev = ".A" }
		if (fields[1] ~ "1$") { patchrev = ".B" }
		if (fields[1] ~ "2$") { patchrev = ".C" }
		sub ("^[^ ]* *", "Patch#" fields[3] "_" fields[2] patchrev " ")
	}
	if ($1 in engtoeng) { sub ($1, engtoeng[$1]); }

    if ($0 ~ " - install") {
        fpinst[$1] = 1
        line[$1] = NR
    } else if ($0 ~ " - deinstall") {
        delete fpinst[$1]
        delete line[$1]
    }

	# If it is an engineering patch that changes the version number ... 
	if ($0 ~ "^Patch#.*_[vV][0-9].*install") {
		sub ("^Patch#", "")
		pname = $0
		sub ("_[vV][0-9].*", "", pname)
		if (patchname[pname] != "") {
			shortname = patchname[pname]
			sub ("^" pname "_[vV]", "")
			if ($0 ~ " - install") { 
				prdebug("e i " shortname " " $1)
				oldpatch[shortname] = version[shortname]
				version[shortname] = $1
				oline[shortname] = line[shortname]
				line[shortname] = NR
			}
			else if ($0 ~ " - deinstall") {
				prdebug("e d " shortname " " $1)
				if (oldpatch[shortname] != "") {
					version[shortname] = oldpatch[shortname]
				}
				delete oldpatch[shortname]
				if (oline[shortname]) {
				    line[shortname] = oline[shortname]
				}
			}
			else { prdebug("u - - -") }
		}
		else { prdebug("u - - -") }
	}
	next
}

$0 ~ /^Patch Tape (patch|Best|4.x)/ {
	# Patch Tape patchC_plus.19971013 install................Finished
	# Patch Tape Best_Recipe.DQ1.19980921 install complete
	# Patch Tape patchDQ4_plus.19980220 install complete
	# Patch Tape Best_Recipe-CD-19981029  install complete

	sub("^Patch Tape (patch|Best|4.x).*[_\.-]","BestRecipe ",$0)

	if ($0 ~ " install(................Finished| complete)") {
		version["BestRecipe"] = $2
		prdebug("p i BestRecipe " $2)
	}
	next
}

/Alexandria : Backup Toolkit/ {
	if ($0 ~ /install complete/) {
		$0 = "Alexandria V4.00.70 PN:1003-XXX-XXXX"
	} 
	else if ($0 ~ /install ABORTED/) {
		next;
	}
}

/ FP#[0-9]+ [vV][0-9]+(\.[0-9]+)+rv[0-9]+/ {	  # has FP + version - is new patch
	name = ""
	while ($0 !~ "^FP#") {     # not done yet ...
		oldname = name
		(name == "") ? name = $1 : name = name " " $1 
		if (name == oldname) {       
			# we are not getting anywhere - danger of infinite loop
			prdebug("L - - -")
			next
		}
		sub("^[ \t]*[^ \t]+[ \t]+", "")
	}
	shortname = nickname[name]
	if (shortname == "") {
		shortname = nickname2[name]
	}
	if (shortname == "") {
		prdebug("u - - -")		# XXX: should this be unique???
		next
	}

	if ($0 ~ "\\(deinstalled\\)") {
		prdebug("f d - " $1)
		delete fpinst[$1]
		delete line[$1]
	}
	else if ($3 == "PN:") {
		prdebug("f i - " $1)
		fpinst[$1] = 1
		line[$1] = NR
		fpver[$1] = $2
		fpprod[$1] = shortname
	}
	next;
}

/ ([vV])?[0-9]+\.[0-9]/ {                  # has version - might be a product?
	name = ""
	while ($0 !~ "^([vV])?[0-9]+\.[0-9]") {     # not done yet ...
		oldname = name
		(name == "") ? name = $1 : name = name " " $1 
		if (name == oldname) {       
			# we are not getting anywhere - danger of infinite loop
			prdebug("L - - -")
			next
		}
		sub("^[ \t]*[^ \t]+[ \t]+", "")
	}
	if (name ~ " Service Pack") {
		# Disgusting service pack description method - treat as engpatch
		sub(" Service Pack", "", name);
		shortname = nickname[name]
		if (shortname == "") {
			shortname = nickname2[name]
		}
		if (shortname == "") {
			prdebug("u - - -")
			next
		}
		else {                         # recognized service pack product
			sub("^[vV]", "")
			if ($1 ~ "sp[0-9]+$") { 
				sub("sp", ".", $1); 
			}
			else {
				prdebug("u - - -")
				next
			}
			ver = $1
			sub("^[^ \t]+[ \t]+", "")

			if ($0 ~ "\\(deinstalled\\)") {
				prdebug("e d " shortname " " ver)
				if (oldpatch[shortname] != "") {
					version[shortname] = oldpatch[shortname]
				}
				delete oldpatch[shortname]
				if (oline[shortname]) {
				    line[shortname] = oline[shortname]
				}
			}
			else if ($0 ~ "^PN:") {
				prdebug("e i " shortname " " ver)
				oldpatch[shortname] = version[shortname]
				version[shortname] = ver
				oline[shortname] = line[shortname]
				line[shortname] = NR
			}
			else { prdebug("u - - -") }
		}
		next
	}

	shortname = nickname[name]
	if (shortname == "") {
		shortname = nickname2[name]
	}
	if (shortname == "") {
		prdebug("u - - -")
		next
	}
	else {                         # recognized product
		sub("^[vV]", "")
		# A nasty hack to remove the x1 extension from fcha versions
		if (shortname == "fcha") {
			if ($1 ~ "x[0-9]$") {
				sub("x[0-9]$", "", $1);
			}
		}
		ver = $1
		# A secondary nasty hack to handle online diagnostics
		if (shortname == "online-diags-symmetry") {
			if (ver ~ "^2") {
				shortname="online-diags-numa"
			}
		}
		sub("^[^ \t]+[ \t]+", "")
		if ($0 ~ "\\(deinstalled\\)") {
			prdebug("p d " shortname " " ver)
			delete version[shortname]
			delete oldpatch[shortname] 
			delete line[shortname]
			delete oline[shortname]
		}
		else if ($0 ~ "^PN:") {
			prdebug("p i " shortname " " ver)
			if (appzero == 1) { 
				if (ver ~ "^[0-9]+\.[0-9]+\.[0-9]+$") {
					version[shortname] = ver ".0" 
				}
			}
			else { version[shortname] = ver }
			delete oldpatch[shortname] 
			line[shortname] = NR;
			delete oline[shortname]
		}
		next
	}
}

{                                     # still unrecognised ?
	prdebug("u - - -");
}

END {
	origline = ""
	if (vcheck != "") {                       # emulate a .vcheck script
		if ( vcheck in version ) { print "V" version[vcheck] }
		else { print "Vunknown" }
	}

	else {
		for ( shortname in version ) {
			if ((product == "") || (product == shortname)) { 
				patchlist = ""
				if (printfp == 1) {
					# list patches that were installed on current product ver
					for (fpnum in fpinst) {
						if (line[shortname] <= line[fpnum]) {
							if (fpprod[fpnum] == "" || fpprod[fpnum] == shortname) {
								patchlist = patchlist " " fpnum
							}
						}
					}
					prdebug("P - " shortname " " version[shortname] patchlist)
				}
				print shortname, version[shortname] " -" patchlist
			}	
		}
	}
}
' debug="$debug" printfp="$printfp" vcheck="$vcheck" product="$product" makecache="$cachefile" appzero="$appzero" $versionlog
